package com.studio49.exmple.core.aop;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import com.studio49.exmple.common.util.PubUtils;
import com.studio49.exmple.entity.web.sys.User;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.studio49.exmple.core.annotation.SysLogAnnotation;

/**
 * 
 * <PRE>
 * 切点类
 * </PRE>
 * 
 */
@Aspect
@Component
public class SysLogAspect {

	private static final Logger logger = LogManager
			.getLogger(SysLogAspect.class.getName());

//	@Resource(name = "userLogService")
//	public UserLogService userLogService;

	@Pointcut("@annotation(com.studio49.exmple.core.annotation.SysLogAnnotation)")
	public void controllerAspect() {
	}

	/**
	 * 前置通知 用于拦截Controller层记录用户的操作
	 * 
	 * @param joinPoint
	 *            切点
	 */
	@Before("controllerAspect()")
	public void doBefore(JoinPoint joinPoint) {

		try {
			HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
					.getRequestAttributes()).getRequest();
			// 请求的IP
			String clientIp = PubUtils.getRemoteHost(request);
			// 主机ip
			String localIp = PubUtils.getLocalIP();
			Map<String, Object> map = getControllerMethodDescription(joinPoint);
			String soperateObjName = map.get("description").toString();
//			ModuleOperationEnumer moduleName = (ModuleOperationEnumer) map
//					.get("moduleName");
			Short type = Short.valueOf(map.get("type").toString());
			// 读取session中的用户
			User user = PubUtils.getSessionUser(request);
			if (user == null) {
				logger.warn("用户未登陆,不记录日志...");
				return;
			}
			// *========控制台输出=========*//
			logger.debug("=====前置通知开始=====");
			logger.debug("请求方法:"
					+ (joinPoint.getTarget().getClass().getName() + "."
							+ joinPoint.getSignature().getName() + "()"));
			logger.debug("动作类型:" + type);
			logger.debug("方法描述:" + soperateObjName);
			logger.debug("请求人:" + user.getUserName());
			logger.debug("请求IP:" + clientIp);
			logger.debug("主机IP:" + localIp);
			// *========数据库日志=========*//
//			UserLog userLog = new UserLog();
//			userLog.setType(type);
//			userLog.setOperateName(soperateObjName);
//			userLog.setClientIP(clientIp);
//			userLog.setHostIP(localIp);
//			userLog.setUserId(user.getId());
//			userLog.setLoginName(user.getLoginName());
//			userLog.setUserName(user.getUserName());
//			if (address != null) {
//				userLog.setCity(address.getCity());
//			}
//			userLog.setCreateTime(new Date());
//			userLogService.save(userLog);
			// 获取session中上一次记录的日志对象
			logger.debug("=====前置通知结束=====");
		} catch (Exception e) {
			logger.error("==前置通知异常==");
			logger.error("异常信息:{}", e);
			e.printStackTrace();
		}
	}

	/**
	 * 异常通知
	 *
	 */
	@AfterThrowing(pointcut = "controllerAspect()", throwing = "e")
	public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
		try {
			logger.debug("=====异常通知开始=====");
			logger.debug("异常代码:" + e.getClass().getName());
			logger.debug("异常信息:" + e.getMessage());
			logger.debug("异常方法:"
					+ (joinPoint.getTarget().getClass().getName() + "."
							+ joinPoint.getSignature().getName() + "()"));
			logger.debug("方法描述:" + getControllerMethodDescription(joinPoint));
			logger.debug("=====异常通知结束=====");
		} catch (Exception ex) {
			// TODO: handle exception
			logger.error("==异常通知异常==");
			logger.error("异常信息:{}", ex);
			ex.printStackTrace();
		}
	}

	/**
	 * 获取注解中对方法的描述信息 用于Controller层注解
	 *
	 */
	@SuppressWarnings("rawtypes")
	public static Map<String, Object> getControllerMethodDescription(
			JoinPoint joinPoint) throws Exception {
		Map<String, Object> result = new HashMap<String, Object>();
		String targetName = joinPoint.getTarget().getClass().getName();
		String methodName = joinPoint.getSignature().getName();
		Object[] arguments = joinPoint.getArgs();
		Class targetClass = Class.forName(targetName);
		Method[] methods = targetClass.getMethods();
		String description = "";
		int type = 0;
		String moduleName;
		for (Method method : methods) {
			if (method.getName().equals(methodName)) {
				Class[] clazzs = method.getParameterTypes();
				if (clazzs.length == arguments.length) {
					description = method.getAnnotation(SysLogAnnotation.class)
							.description();
					type = method.getAnnotation(SysLogAnnotation.class).type();
					moduleName = method.getAnnotation(SysLogAnnotation.class)
							.moduleName();
					result.put("description", description);
					result.put("type", type);
					result.put("moduleName", moduleName);
					break;
				}
			}
		}
		return result;
	}

}
